1 package org.apache.maven.surefire.common.junit48;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.util.ArrayList;
23 import java.util.Collections;
24 import java.util.HashSet;
25 import java.util.List;
26 import java.util.Map;
27 import java.util.Properties;
28 import java.util.Set;
29
30 import org.apache.maven.shared.utils.io.SelectorUtils;
31 import org.apache.maven.surefire.booter.ProviderParameterNames;
32 import org.apache.maven.surefire.group.match.AndGroupMatcher;
33 import org.apache.maven.surefire.group.match.GroupMatcher;
34 import org.apache.maven.surefire.group.match.InverseGroupMatcher;
35 import org.apache.maven.surefire.group.parse.GroupMatcherParser;
36 import org.apache.maven.surefire.group.parse.ParseException;
37 import org.junit.experimental.categories.Category;
38 import org.junit.runner.Description;
39 import org.junit.runner.manipulation.Filter;
40
41
42
43
44 public class FilterFactory
45 {
46 private final ClassLoader testClassLoader;
47
48 public FilterFactory( ClassLoader testClassLoader )
49 {
50 this.testClassLoader = testClassLoader;
51 }
52
53 public Filter createGroupFilter( Properties providerProperties )
54 {
55 String groups = providerProperties.getProperty( ProviderParameterNames.TESTNG_GROUPS_PROP );
56 String excludedGroups = providerProperties.getProperty( ProviderParameterNames.TESTNG_EXCLUDEDGROUPS_PROP );
57
58 GroupMatcher included = null;
59 if ( groups != null && groups.trim().length() > 0 )
60 {
61 try
62 {
63 included = new GroupMatcherParser( groups ).parse();
64 }
65 catch ( ParseException e )
66 {
67 throw new IllegalArgumentException( "Invalid group expression: '" + groups + "'. Reason: "
68 + e.getMessage(), e );
69 }
70 }
71
72 GroupMatcher excluded = null;
73 if ( excludedGroups != null && excludedGroups.trim().length() > 0 )
74 {
75 try
76 {
77 excluded = new GroupMatcherParser( excludedGroups ).parse();
78 }
79 catch ( ParseException e )
80 {
81 throw new IllegalArgumentException( "Invalid group expression: '" + excludedGroups + "'. Reason: "
82 + e.getMessage(), e );
83 }
84 }
85
86 if ( included != null && testClassLoader != null )
87 {
88 included.loadGroupClasses( testClassLoader );
89 }
90
91 if ( excluded != null && testClassLoader != null )
92 {
93 excluded.loadGroupClasses( testClassLoader );
94 }
95
96 return new GroupMatcherCategoryFilter( included, excluded );
97 }
98
99 public Filter createMethodFilter( String requestedTestMethod )
100 {
101 return new MethodFilter( requestedTestMethod );
102 }
103
104 public Filter createFailingMethodFilter( Map<Class<?>, Set<String>> failingClassMethodMap )
105 {
106 return new FailingMethodFilter( failingClassMethodMap );
107 }
108
109 public Filter and( Filter filter1, Filter filter2 )
110 {
111 return new AndFilter( filter1, filter2 );
112 }
113
114 private static class MethodFilter
115 extends Filter
116 {
117 private final String requestedTestMethod;
118
119 public MethodFilter( String requestedTestMethod )
120 {
121 this.requestedTestMethod = requestedTestMethod;
122 }
123
124 @Override
125 public boolean shouldRun( Description description )
126 {
127 for ( Description o : description.getChildren() )
128 {
129 if ( isDescriptionMatch( o ) || shouldRun( o ) )
130 {
131 return true;
132 }
133
134 }
135 return isDescriptionMatch( description );
136 }
137
138 private boolean isDescriptionMatch( Description description )
139 {
140 return description.getMethodName() != null
141 && SelectorUtils.match( requestedTestMethod, description.getMethodName() );
142 }
143
144 @Override
145 public String describe()
146 {
147 return "By method" + requestedTestMethod;
148 }
149 }
150
151
152 private static class FailingMethodFilter
153 extends Filter
154 {
155
156 private final Map<Class<?>, Set<String>> failingClassMethodMap;
157
158 public FailingMethodFilter( Map<Class<?>, Set<String>> failingClassMethodMap )
159 {
160 this.failingClassMethodMap = failingClassMethodMap;
161 }
162
163 @Override
164 public boolean shouldRun( Description description )
165 {
166 return isDescriptionMatch( description );
167 }
168
169 private boolean isDescriptionMatch( Description description )
170 {
171 if ( description.getTestClass() == null || description.getMethodName() == null )
172 {
173 for ( Description childrenDescription : description.getChildren() )
174 {
175 if ( isDescriptionMatch( childrenDescription ) )
176 {
177 return true;
178 }
179 }
180 return false;
181 }
182
183 Set<String> testMethods = failingClassMethodMap.get( description.getTestClass() );
184 return testMethods != null && testMethods.contains( description.getMethodName() );
185 }
186
187 @Override
188 public String describe()
189 {
190 return "By failing class method";
191 }
192 }
193
194 private static class GroupMatcherCategoryFilter
195 extends Filter
196 {
197
198 private final AndGroupMatcher matcher;
199
200 public GroupMatcherCategoryFilter( GroupMatcher included, GroupMatcher excluded )
201 {
202 GroupMatcher invertedExclude = excluded == null ? null : new InverseGroupMatcher( excluded );
203 if ( included != null || invertedExclude != null )
204 {
205 matcher = new AndGroupMatcher();
206 if ( included != null )
207 {
208 matcher.addMatcher( included );
209 }
210
211 if ( invertedExclude != null )
212 {
213 matcher.addMatcher( invertedExclude );
214 }
215 }
216 else
217 {
218 matcher = null;
219 }
220 }
221
222 @Override
223 public boolean shouldRun( Description description )
224 {
225 if ( description.getMethodName() == null || description.getTestClass() == null )
226 {
227 return shouldRun( description, null, null );
228 }
229 else
230 {
231 return shouldRun( description, Description.createSuiteDescription( description.getTestClass() ),
232 description.getTestClass() );
233 }
234 }
235
236 private static void findSuperclassCategories( Set<Class<?>> cats, Class<?> clazz )
237 {
238 if ( clazz != null && clazz.getSuperclass() != null )
239 {
240 Category cat = clazz.getSuperclass().getAnnotation( Category.class );
241 if ( cat != null )
242 {
243 Collections.addAll( cats, cat.value() );
244 }
245 else
246 {
247 findSuperclassCategories( cats, clazz.getSuperclass() );
248 }
249 }
250 }
251
252 private boolean shouldRun( Description description, Description parent, Class<?> parentClass )
253 {
254 if ( matcher == null )
255 {
256 return true;
257 }
258 else
259 {
260 Set<Class<?>> cats = new HashSet<Class<?>>();
261 Category cat = description.getAnnotation( Category.class );
262 if ( cat != null )
263 {
264 Collections.addAll( cats, cat.value() );
265 }
266
267 if ( parent != null )
268 {
269 cat = parent.getAnnotation( Category.class );
270 if ( cat != null )
271 {
272 Collections.addAll( cats, cat.value() );
273 }
274 }
275
276 if ( parentClass != null )
277 {
278 findSuperclassCategories( cats, parentClass );
279 }
280
281 Class<?> testClass = description.getTestClass();
282 if ( testClass != null )
283 {
284 cat = testClass.getAnnotation( Category.class );
285 if ( cat != null )
286 {
287 Collections.addAll( cats, cat.value() );
288 }
289 }
290
291 cats.removeAll( Collections.<Class<?>>singleton( null ) );
292
293 boolean result = matcher.enabled( cats.toArray( new Class<?>[cats.size()] ) );
294
295 if ( !result )
296 {
297 ArrayList<Description> children = description.getChildren();
298 if ( children != null )
299 {
300 for ( Description child : children )
301 {
302 if ( shouldRun( child, description, null ) )
303 {
304 result = true;
305 break;
306 }
307 }
308 }
309 }
310
311 return result;
312 }
313 }
314
315 @Override
316 public String describe()
317 {
318 return matcher == null ? "ANY" : matcher.toString();
319 }
320 }
321
322 private static class AndFilter
323 extends Filter
324 {
325 private final Filter filter1;
326
327 private final Filter filter2;
328
329 public AndFilter( Filter filter1, Filter filter2 )
330 {
331 this.filter1 = filter1;
332 this.filter2 = filter2;
333 }
334
335 @Override
336 public boolean shouldRun( Description description )
337 {
338 return filter1.shouldRun( description ) && filter2.shouldRun( description );
339 }
340
341 @Override
342 public String describe()
343 {
344 return filter1.describe() + " AND " + filter2.describe();
345 }
346 }
347
348 @SuppressWarnings( "unused" )
349 private static class CombinedCategoryFilter
350 extends Filter
351 {
352 private final List<Filter> includedFilters;
353
354 private final List<Filter> excludedFilters;
355
356 public CombinedCategoryFilter( List<Filter> includedFilters, List<Filter> excludedFilters )
357 {
358 this.includedFilters = includedFilters;
359 this.excludedFilters = excludedFilters;
360 }
361
362 @Override
363 public boolean shouldRun( Description description )
364 {
365 return ( includedFilters.isEmpty() || inOneOfFilters( includedFilters, description ) )
366 && ( excludedFilters.isEmpty() || !inOneOfFilters( excludedFilters, description ) );
367 }
368
369 private boolean inOneOfFilters( List<Filter> filters, Description description )
370 {
371 for ( Filter f : filters )
372 {
373 if ( f.shouldRun( description ) )
374 {
375 return true;
376 }
377 }
378 return false;
379 }
380
381 @Override
382 public String describe()
383 {
384 StringBuilder sb = new StringBuilder();
385 if ( !includedFilters.isEmpty() )
386 {
387 sb.append( "(" );
388 sb.append( joinFilters( includedFilters, " OR " ) );
389 sb.append( ")" );
390 if ( !excludedFilters.isEmpty() )
391 {
392 sb.append( " AND " );
393 }
394 }
395 if ( !excludedFilters.isEmpty() )
396 {
397 sb.append( "NOT (" );
398 sb.append( joinFilters( includedFilters, " OR " ) );
399 sb.append( ")" );
400 }
401
402 return sb.toString();
403 }
404
405 private String joinFilters( List<Filter> filters, String sep )
406 {
407 boolean isFirst = true;
408 StringBuilder sb = new StringBuilder();
409 for ( Filter f : filters )
410 {
411 if ( !isFirst )
412 {
413 sb.append( sep );
414 }
415 sb.append( f.describe() );
416 isFirst = false;
417 }
418 return sb.toString();
419 }
420 }
421 }